package org.zjt.threadlocal;

import com.alibaba.ttl.TransmittableThreadLocal;
import com.alibaba.ttl.TtlRunnable;
import com.alibaba.ttl.threadpool.TtlExecutors;

import lombok.extern.slf4j.Slf4j;

import java.util.Arrays;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;

/**
 * @author juntao.zhang
 * @version V1.0
 * @Description: TODO
 * @Package org.zjt.threadlocal
 * @date 2018/3/15 23:33
 */
@Slf4j
public class TransmittableThreadLocalTest {




    /**
     * 父子线程的穿透、相当于   InheritableThreadLocal + Update
     */
    public static void TransmittableRunnableParentThread() {

        ExecutorService executorService = Executors.newFixedThreadPool(1);
        TransmittableThreadLocal<String> parent = new TransmittableThreadLocal<>();

        parent.set("Transmittable-set-in-parent");
        Runnable task = new Task("1",parent);
        Runnable ttlRunnable = TtlRunnable.get(task);
        executorService.submit(ttlRunnable);


        parent.set("Transmittable-set-in-parent-2");
        ttlRunnable = TtlRunnable.get(new Task("2",parent));
        executorService.submit(ttlRunnable);

        executorService.shutdown();
    }


    /**
     * InheritableThreadLocal
     *
     * 只能对子线程传递一次，不能update。
     *
     * 一旦子线程实例化成功，以后重新改变再不会生效。
     */
    public static void InheritableRunnableThreadLocalTest() {
        ExecutorService executorService = Executors.newFixedThreadPool(1);
        InheritableThreadLocal<String>  inheritableThreadLocal = new InheritableThreadLocal();

        inheritableThreadLocal.set("Inheritable-set-in-parent");
        Runnable task = new Task("1",inheritableThreadLocal);
        executorService.submit(task);

        /**  对子线程无效的update  **/
        inheritableThreadLocal.set("Inheritable-set-in-parent-2");
        task = new Task("2",inheritableThreadLocal);
        executorService.submit(task);

        executorService.shutdown();
    }





    public static void TransmittableThreadPool() {
        ExecutorService executorService = TtlExecutors.getTtlExecutorService(Executors.newFixedThreadPool(1));

        TransmittableThreadLocal<String> parent = new TransmittableThreadLocal<String>();
        parent.set("value-set-in-parent-1");

        Runnable task = new Task("1",parent);

        parent.set("value-set-in-parent-2");
        Callable call = new CallableFask("2",parent);
        executorService.submit(task);
        executorService.submit(call);


        parent.set("value-set-in-parent-3");
        call = new CallableFask("3",parent);
        executorService.submit(call);
    }






    public static void main(String[] args) {

        TransmittableRunnableParentThread();
        log.info("---------------------------------------------");
        InheritableRunnableThreadLocalTest();



        TransmittableThreadPool();
    }




    @Slf4j
    public static class CallableFask implements Callable<String>{

        private final String msg ;

        private final ThreadLocal<String>[] threadLocals;

        public CallableFask(String msg, ThreadLocal<String> ... threadLocals) {
            this.msg = msg;
            this.threadLocals = threadLocals;
        }

        @Override
        public String call() throws Exception {
            List<String> collect = Arrays.stream(threadLocals).map(ThreadLocal::get).collect(Collectors.toList());
            log.info("collect:{} \t msg:{}",collect,msg);
            return msg.toUpperCase() + String.join(",",collect);
        }
    }
}
